#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <stdbool.h>
#include<sys/socket.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<sys/select.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<sys/errno.h>
#include<strings.h>

#define MEM_SHARE (8096*125)
#define SHM_SHARE_INDEX 5
//TODO: 开始从内存中获取所有的数据的更新
#define COMPLETE_INDEX 0x1234

static int32_t MAIN_DRIVER_PID; //TODO: 主驱动的进程号
//TODO:信号响应之后，立即检测 cache 是否更新完成,更新完成响应状态标志位
//TODO:获取通信线程的进程号，和版本号，需要相应的中断的相应的函数，当前维护的版本号
//TODO： 检测事件的发生，一旦有修改，就会对配置进行更新 (UDP传输,Local 不考虑 TCP)
//TODO: 命令列表和命令的信号列表形成映射关系

enum CACHE_TYPE_E{
    CACHE_UPDATE = 0x1,
    CACHE_NO_CHANGE = 0x2,
    CACHE_FIRST_CREATE = 0x3
};

struct csv{
    unsigned char mem_status; //当前内存页是否为更新的状态
    int cache_mem_offset;
    int id;                    //TODO: signal index,发送的信号的使用的index的值
    char name[128];
    char value[100];
    char type[10];
    unsigned char mode;
    unsigned char attr; // 当前页的位置在缓存池中的的位置
    unsigned short pages_crc; //对页中的数据进行crc校验
};

//最大分页多分配一页,为了保证在共享内存中永远可以使用
struct cache_mem{
    #define MAX_PAGES ((MEM_SHARE)/sizeof(struct csv)+1)
    int begin_pages_empty_index;                        //  空的页表起始索引值
    int end_pages_empty_index;                          //  空的页表终止索引值
    int begin_pages_full_index;                         //  目前查询页的位置
    int end_pages_full_index;                           //  满页表索引位置
    struct csv* pages_index_record[MAX_PAGES];                 //  记录维护的cache_mem的空间,状态标志位,1,当前页正在被使用,-1,转台不明,0,未被使用
    struct csv* full_pages[MAX_PAGES];                         //  满页记录空间
    struct csv* empty_pages[MAX_PAGES];                        //  记录的空闲的的页
    unsigned short mem_crc_pages[MAX_PAGES];            //  原始CRC页表的使用
    struct csv pages[MAX_PAGES];                         //  抽象出来的缓存池
    int cavity_pages_cnt;                               //  空洞页计数
};

static struct cache_mem *shm_share_addr;

void shmm_init(void){
    //TODO: TEST mem init check if ok ?  check key if exit not exit error addr is (void*)-1
    shm_share_addr = (struct cache_mem*)shmat(SHM_SHARE_INDEX,0,0); 
    
    if(shm_share_addr == (void*)-1){
        printf("Init MEM SHARE ERROR: %s\n\n",strerror(errno)); 
        printf("**May Be Main Driver Error,Please Check Your Main Driver !!!**\n");
        exit(1);
    }
}

void shmm_exit(void){
    shmdt((void*)shm_share_addr); //TODO： 测试内存映射是否成功解除 
}

void parse_cmd_spilt(char* line,char (*res)[256][128]){ //不加指针是无法完成数据的修改
     char* ptr = NULL;
     int32_t index = 0;
    
     if(line == NULL){
         printf("cmd is null\n");
         return;
     }

     while((ptr = strsep(&line," ")) != NULL){
         if(index > 256){
             printf("Error: cmds are over limit,Please check your input cmds\n");
             return; //只是提示相关的打印信息
         }
          memcpy((*res)[index],ptr,strlen(ptr));
          index++;
     }
}

char *dupstr(char *s) { // FIXME: free 一次就可以
	char *r;
	r = (char *) calloc(strlen(s) + 1, sizeof(char));
	strcpy(r, s);
	return (r);
}

/* 创建一个 STACK 结构 CMD= 256 条命令进行使用,最大容纳256条指令* 
 * 信号的检测范围 2 ～ 255 之间进行检测
 * */

static char* command_list[256] = {
    [0] = "exit",
    [1] = "quit",
    [2] = "complete",   //TODO: 重新获取命令不全的列表,siglist 是变化的
    [3] = "help",       //TODO: 需要遍历所有的方式方法，进行不同的打印
    [4] = "?",
    [255] = (char*)NULL
};

//x为检测的索引位数的索引
//y为需要设置掩码的数
//初始化时需要设置相应的掩码位，代表信号的数值

#define check_bit(x,y) ((y)&(1<<(x))?1:0
#define set_bit(x,y) y|=(1<<(x))) 

char *cmd_generator(const char *text, int state) {
	static int i, len;
	char *name;
	if (!state) {
		i = 0;
		len = (int) strlen(text);
	}

	while(name = command_list[i]) { //检索命令行并进行补全;
		i++;
		if (strncmp(name, text, len) == 0) {
			return dupstr(name);
		}
	}

	return NULL;
}

void udp_config(void){

}

char **debug_cli_completion(const char *text, int start, int end) {
	char **matches;
	matches = (char **) NULL;
	if (start == 0) {
		matches = rl_completion_matches(text, cmd_generator);
	}
	return matches;
}

void init_readline(void) {
	rl_readline_name = "sak -> ";
	rl_attempted_completion_function = debug_cli_completion;
}

char *stripwhite(char *string) {
	register char *s, *t;
	for (s = string; whitespace(*s); s++) { ;
	}
	if (*s == 0) {
		return s;
	}
	t = s + strlen(s) - 1;
	while (t > s && whitespace(*t)) {
		t--;
	}
	*++t = 0;
	return s;
}

//TODO: check signal index for salver shell
//FIXME: Not Need check bit map using

struct cmd_t{
  int32_t id;
  unsigned char cmd[10][128]; //TODO:最多处理10个参数  
};

bool send_sig(int32_t signum,struct cmd_t ct){
    union sigval val_t;
    val_t.sival_ptr = &ct;
    int32_t ret = sigqueue(MAIN_DRIVER_PID,signum,val_t); //FIXME： 设置信号发送的功能
    
    if(ret != 0){
        printf("Send Sig val Error: %s\n",strerror(errno));
        return false;
    }
    return true;
}

//FIXME: 命令行的长度不应该超过128个字节
//

bool check_mem_status(enum CACHE_TYPE_E type){
    switch(type){
        case CACHE_FIRST_CREATE:
        case CACHE_UPDATE:
        case CACHE_NO_CHANGE:
        default:
           return false; 
    }
    return true;
}

void exec_cmd(char res[10][128]){ //TODO：还需要使用一个shm id 作为内存共享的方法
     int32_t i = 0;
     int32_t j = 0;
     int32_t cnt = 0;
     struct cmd_t ct;

     for(i = 0 ; i < 10 ; i++){
         if(res[i][0] == 0){ //TODO：如果是空字符就会退出
             break;
         }
         memcpy((char*)ct.cmd[i],(char*)res[i],strlen((char*)res[i]));
     }

     if(shm_share_addr->pages[0].mem_status ){
         printf("No Share mem for shell \n");
     }
     while(strcmp(res[0],shm_share_addr->pages[cnt].name)){
         if(cnt > 256){
             printf("Can't find cmd in list,Please Check your command\n");
             return;
         }
        cnt++;
     }

    char info[32];
    ct.id = shm_share_addr->pages[cnt].id;

    if(!send_sig(10,ct)){ //TODO:查看信号是否发送成功,触发命令相应
        return;
    }

    switch(shm_share_addr->pages[cnt].mem_status){
        case CACHE_UPDATE:
            strcpy(info,"Mem update");
            break;
        case CACHE_NO_CHANGE:
            strcpy(info,"Mem not change");
            break;
        case CACHE_FIRST_CREATE:
             strcpy(info,"Mem first create");
            break;
            default:
            printf("Mem Status not delcare !!!\n");
            return;
    }    

    printf("Cmd Info: %s \n",info);
    printf("%s\n",shm_share_addr->pages[cnt].value); //FIXME: 查看查询到的值
}

void parse_cmd(char* cmd){ //TODO： 解析命令
    //FIXME:如果命令为空,就不再处理退出命令退出
     if(cmd == NULL)
         return;

     if(!check_mem_status(shm_share_addr->pages[0].mem_status)){
         printf("Not Find Cmd in Mem list\n");
         return;   
     }

     int32_t cmd_size = strlen(cmd);
     char res[256][128]={0}; //TODO: 256个命令，每个命令最长为256个字节，进行使用
     parse_cmd_spilt(cmd,&res);
     exec_cmd(res);
}

int main(int argc, char **argv) {
	char *line, *s;
	init_readline();
    shmm_init();

	while (1) {
		line = readline("\033[33msak -> ");
		if (!line) break;
		s = stripwhite(line);
		if (*s) {
			add_history(s);
			if (!strcmp(s, "exit") || !strcmp(s, "quit") || !strcmp(s, "bye")) {
                printf("quit sak tools ... ...\n");
                shmm_exit(); //FIXME: 内存解除映射时可能存在某些问题，需要特别记录,easy to record some thing                                                     
				exit(0);
			}
            parse_cmd(s);
		}
		free(line);
		line = NULL;
	}
	exit(0);
}
